﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ControlExtensions;

namespace WSNs
{
    public partial class Ctl_NodesTopology : UserControl
    {
        #region Fields

        public Action<AcqStructure,double> AcqStructChangeEvent; //传递CtlNode的AcqStructChangeEvent至Form1，用于串口发送数据
        private NodesData _nodesData = NodesData.GetInstance();

        private Pen _penback;
        private Pen _penline;
        private Color _colorEllipse; //拓扑节点颜色
        private readonly Pen _pen = new Pen(Color.MediumSeaGreen, 6); //画笔颜色
        private readonly Font _f = new Font("Verdana", 12, FontStyle.Bold);
        private Point _pointnodes; //子节点坐标

        //public int[,] LQIValue = new int[10, 2];
        public Dictionary<int, int> _LQIValue = new Dictionary<int, int>(); 
        private readonly Random _r = new Random();
        private List<int> _delayTimeList = new List<int>(); //路由退避时间表
        #endregion

        #region Public

        public Ctl_NodesTopology()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
                          ControlStyles.ResizeRedraw |
                          ControlStyles.AllPaintingInWmPaint, true);
        }

        /// <summary>
        /// 获取所有节点
        /// </summary>
        /// <returns></returns>
        //public List<int> GetAllNodes()
        //{
            
        //}

        /// <summary>
        /// 删除所有节点拓扑
        /// </summary>
        public void RemoveAllNodesTopo()
        {
            _delayTimeList.Clear();
            List<CtlNode> listTemp = this.Controls.OfType<CtlNode>().Where(node => node.NodeID != 0).ToList();
            for (int i = 0; i < listTemp.Count; i++)
            {
                this.Controls.Remove(listTemp[i]);
            }
        }

        public void RemoveSelectedNodeTopo(int id)
        {
            Dictionary<int, int> dicTemp = GetAllTopoDic();
            List<int> listChilds = new List<int>();
            int nodeId,fatherId;
            fatherId = dicTemp[id];
            foreach (KeyValuePair<int, int> i in dicTemp) //获取该节点所有的子节点
            {
                if (i.Value.Equals(id))
                    listChilds.Add(i.Key);
            }
            foreach (CtlNode node in this.Controls.OfType<CtlNode>()) //将这些子节点的父节点设置为该节点的父节点
            {
                if (listChilds.Contains(node.NodeID))
                    node.FatherNode = fatherId;
            }
            if (GetSelectedCtlNode(id) != null)
                this.Controls.Remove(GetSelectedCtlNode(id));
        }

        /// <summary>
        /// 获取指定节点
        /// </summary>
        /// <param name="id">节点ID</param>
        /// <returns></returns>
        public CtlNode GetSelectedCtlNode(int id)
        {
            return this.Controls.OfType<CtlNode>().FirstOrDefault(node => node.NodeID == id);
        }

        /// <summary>
        /// 获取所有采集节点
        /// </summary>
        /// <returns></returns>
        public List<CtlNode> GetAllEndNode()
        {
            return this.Controls.OfType<CtlNode>().Where(node => node.NodeType == NodesType.EndNode).ToList();
        }

        /// <summary>
        /// 获取节点拓扑结构
        /// </summary>
        /// <returns>key为本节点号,value为父节点号</returns>
        public Dictionary<int, int> GetAllTopoDic()
        {
            Dictionary<int, int> dicTemp = new Dictionary<int, int>();
            foreach (CtlNode node in this.Controls.OfType<CtlNode>())
            {
                if (node.NodeID != 0)
                    dicTemp.Add(node.NodeID, node.FatherNode);
            }
            return dicTemp;
        }
        public void UpdateTopo()
        {
            //跨线程调用控件时需要
            this.UIThreadInvoke(delegate { this.Refresh(); });
        }

        /// <summary>
        /// 更新所有节点的参数
        /// </summary>
        /// <param name="acq"></param>
        public void UpdataAllAcq(AcqStructure acq)
        {
            foreach (Control control in this.Controls)
            {
                if (control as CtlNode != null)
                {
                    CtlNode node = (CtlNode)control;
                    if (node.NodeID != 0)
                        node.AcqStructure = acq;
                }
            }
        }

        /// <summary>
        /// 更新指定节点参数
        /// </summary>
        /// <param name="nodeID"></param>
        /// <param name="acq"></param>
        public void UpdataNodeAcq(int nodeID, AcqStructure acq)
        {
            foreach (CtlNode node in this.Controls.OfType<CtlNode>().Where(node => node.NodeID == nodeID))
                node.AcqStructure = acq;
        }

        /// <summary>
        /// 初始化DelayList全为-1，-1表示空位，添加网关在第一位置
        /// </summary>
        public void DelayListInit(int count)
        {
            _delayTimeList.Clear();
            for (int i = 0; i < count; i++)
            {
                _delayTimeList.Add(-1);
            }
            if (count != 0)
                _delayTimeList[0] = 0;
        }
        
        /// <summary>
        /// 添加节点
        /// </summary>
        /// <param name="node"></param>
        public bool AddnodeTopo(CtlNode node)
        {
            if (this.Controls.Cast<CtlNode>().Any(n => n.NodeID == node.NodeID)) //检查节点号是否存在
            {
                MessageBox.Show("该节点"+node.NodeID.ToString()+"已存在！", "添加错误");
                return false;
            }
            foreach (CtlNode n in from Control control in this.Controls where control as CtlNode != null select (CtlNode)control into n where n.NodeID == node.FatherNode select n)
            {
                if (n.NodeType == NodesType.EndNode)
                {
                    MessageBox.Show("采集节点不能做为父节点！");
                    return false;
                }
                if (node.NodeType != NodesType.Router) return AddNodes(node);
                return AddDelayList(node.NodeID, node.FatherNode) && AddNodes(node);
            }
            MessageBox.Show( "父节点不存在或者节点号错误！","添加错误");
            return false;
        }

        /// <summary>
        /// 获取路由退避时间间隔list，包括 路由启动时间标志（0x07）,路由地址，网关——>路由的下一地址，基本退避时间间隔，几个间隔
        /// </summary>
        /// <returns></returns>
        public List<byte> GetRouterDelayTimeList(int routerID,int fatherID)
        {
            int nodeTemp;
            int delayTime = 0;
            List<byte> lb = new List<byte>();
            lb.Add(0x07);
            //router在father前
            delayTime = _delayTimeList.IndexOf(routerID) < _delayTimeList.IndexOf(fatherID)
                ? _delayTimeList.Count - _delayTimeList.IndexOf(fatherID) + _delayTimeList.IndexOf(routerID)
                : _delayTimeList.IndexOf(routerID) - _delayTimeList.IndexOf(fatherID);

            nodeTemp = GetNextNodeOfGetway(routerID);
            lb.Add((byte) routerID);
            lb.Add((byte)nodeTemp);
            switch (_delayTimeList.Count) //基本退避时间间隔
            {
                case 8:
                case 32:
                    lb.Add(0x04);
                    break;
                case 16:
                case 64:
                    lb.Add(0x02);
                    break;
            }
            lb.Add((byte) delayTime);

            return lb;
        }

        /// <summary>
        /// 获取 网关节点——>本节点 的下一跳地址
        /// </summary>
        /// <param name="nodeID">本节点地址</param>
        /// <returns></returns>
        public int GetNextNodeOfGetway(int nodeID)
        {
            int nextTemp = nodeID;
            int fatherID = nodeID;
            while (fatherID != 0)
            {
                foreach (CtlNode node in from Control control in this.Controls where control as CtlNode != null select (CtlNode)control into node where node.NodeID == fatherID select node)
                {
                    fatherID = node.FatherNode; //获取上级父节点
                    nextTemp = node.NodeID;
                    break;
                }
            }
            return nextTemp;
        }

        #endregion

        private bool AddDelayList(int id, int fatherid)
        {
            if (_delayTimeList.Count == 0)
            {
                MessageBox.Show("单跳网络，不能添加路由"); 
                return false;
            }
            int temp = _delayTimeList.FindIndex(2, i => i == -1); //搜索空余位置
            while (_delayTimeList.FindIndex(0, i => i == fatherid) + 2 > temp) //找到父节点加1之后的空余位，跳出while
            {
                temp = _delayTimeList.FindIndex(temp + 1, i => i == -1); //空余位置在父节点之前，搜索下一个空余位置
                if (temp != -1) continue;
                temp = _delayTimeList.FindIndex(0, fatherid, i => i == -1);
                if (temp == -1) //没有位置
                {
                    MessageBox.Show("超出最大路由限制（加上网关）", "加入网络错误");
                    return false;
                }
                _delayTimeList[temp] = id;
                return true;
            }
            _delayTimeList[temp] = id;
            return true;
        }
        
        #region Override

        protected override void OnLoad(EventArgs e)
        {
            _penback = new Pen(Brushes.Green, 1);
            _penback.DashStyle = DashStyle.Dot;
            this.BackColor = Color.Black;

            AddGetway();
            DelayListInit(8);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Draw(e.Graphics);

            this.Update();
        }
        
        #endregion

        #region Draw

        private void Draw(Graphics g)
        {
           // Pen myPen = new Pen(Color.FromArgb(220, 20,60));
            Font MyFont1 = new Font("宋体", 8, FontStyle.Bold);

            g.SmoothingMode = SmoothingMode.HighSpeed;
            g.Clear(this.BackColor);
            DrawBackground(g);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            DrawLines(g);

            //if (_nodesData.GetShowNodes().Count != 0)
           // {
                foreach (var key in _LQIValue.Keys)
                {
                    g.DrawString("节点"+key+"的LQI值：" + _LQIValue[key], MyFont1, Brushes.AliceBlue, 580, 20+(key-1)*20);
                }
          //  }
        }

        private void DrawBackground(Graphics g)
        {
            for (int i = 0; i < this.Height; i += 12)
                g.DrawLine(_penback, new Point(0, i), new Point(this.Width, i)); //画横线
            for (int i = 0; i < this.Width; i += 12)
                g.DrawLine(_penback, new Point(i, 0), new Point(i, this.Height)); //画竖线
        }

        private void DrawLines(Graphics g)
        {
            Dictionary<int, PointF> pointTemp = new Dictionary<int, PointF>();
            foreach (Control control in this.Controls)
            {
                if (control as CtlNode == null) continue;
                CtlNode node = (CtlNode)control;
                if (pointTemp.Keys.Contains(node.NodeID)) continue;
                pointTemp.Add(node.NodeID, node.HotPoint);
            }
            foreach (Control control in this.Controls)
            {
                if (control as CtlNode == null) continue;
                CtlNode node = (CtlNode)control;
                if (node.NodeType == NodesType.Coordinator) continue;
                //if (node.ChildNodes == null) continue;
                //for (int i = 0; i < node.ChildNodes.Count; i++)
                //{
                    g.DrawLine(new Pen(Brushes.SlateBlue, 3), node.HotPoint, pointTemp[node.FatherNode]);
                //}
            }
        }
        private void Ctl_NodesTopology_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;
            this.Invalidate();
        }

        private void AddGetway()
        {
            CtlNode cn = new CtlNode();
            cn.Text = "G";
            cn.Location = new Point(150, 150);
            this.Controls.Add(cn);
            cn.MouseMove += Ctl_NodesTopology_MouseMove;
        }

        private bool AddNodes(CtlNode node)
        {
            CtlNode cn = new CtlNode();
            cn.Text = node.Text;
            cn.NodeType = node.NodeType;
            cn.FatherNode = node.FatherNode;
            cn.Location = new Point(_r.Next(this.Width), _r.Next(this.Height));
            this.Controls.Add(cn);
            cn.MouseMove += Ctl_NodesTopology_MouseMove;
            cn.AcqStructChangeEvent += CtlNode_AcqStructChangeEvent;
            cn.DeleteNodeEvent += CtlNode_DeleteNodeEvent;
            return true;
        }

        private void CtlNode_AcqStructChangeEvent(AcqStructure acq,double sensitivity)
        {
            AcqStructChangeEvent(acq,sensitivity);
        }

        private void CtlNode_DeleteNodeEvent(int id)
        {
            RemoveSelectedNodeTopo(id);
            this.Invalidate();
        }
        #endregion       
    }
}
